package cn.bugstack.springframework.beans.factory.support;
// 实例化 Bean 类(AbstractAutowireCapableBeanFactory)
// 创建策略调用
import cn.bugstack.springframework.beans.BeanException;
import cn.bugstack.springframework.beans.PropertyValue;
import cn.bugstack.springframework.beans.PropertyValues;
import cn.bugstack.springframework.beans.factory.config.BeanDefinition;
import cn.bugstack.springframework.beans.factory.config.BeanReference;
import cn.hutool.core.bean.BeanUtil;

import java.lang.reflect.Constructor;


public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory{
    // 首先在 AbstractAutowireCapableBeanFactory 抽象类中定义了一个创建对象的实
    // 例化策略属性类 InstantiationStrategy instantiationStrategy，
    // 这里我们选择了 Cglib 的实现类。
    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeanException {
        Object bean = null;
        try {
            //在 AbstractAutowireCapableBeanFactory 类中实现了 Bean 的实例化操作newInstance，
            // 其实这块会埋下一个坑，有构造函数入参的对象怎么处理？可以提前思考
            /* 解决这个坑？ 以下实现*/
            bean = createBeanInstance(beanDefinition, beanName,args );
            // 给 Bean 填充属性
            applyPropertyValues(beanName,bean,beanDefinition);
        } catch (Exception e) {
            throw new BeanException("Instantiation of bean failed",e);
        }
        // 在处理完 Bean 对象的实例化后，直接调用 addSingleton 方法存放到单例对象的缓存中去。
        addSingleton(beanName, bean);
        return bean;
    }

    /*
    Bean 属性填充
     */
    protected  void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition){
        //在 applyPropertyValues 中，通过获取beanDefinition.getPropertyValues() 循环进行属性填充操作，
        // 如果遇到的是 BeanReference，那么就需要递归获取 Bean 实例，调用 getBean 方法。
        try {
            PropertyValues propertyValues = beanDefinition.getPropertyValues();
            for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
                String name = propertyValue.getName();
                Object value = propertyValue.getValue();
                if (value instanceof BeanReference){
                    // A 依赖 B ，获取  B 的实例化
                    BeanReference beanReference = (BeanReference) value;
                    value = getBean(beanReference.getBeanName());
                }
                // 属性填充
                BeanUtil.setFieldValue(bean, name, value);
            }
        }catch (Exception e){
            throw new BeanException("Error setting property values:" + beanName);
        }
    }

    // 抽取 createBeanInstance 方法
    protected Object createBeanInstance(BeanDefinition beanDefinition,String beanName,Object[] args){
        // 在这个方法中需要注意 Constructor代表了你有多少个构造函数
        Constructor constructorToUse = null;
        Class<?> beanClass = beanDefinition.getBeanClass();
        // 通过 beanClass.getDeclaredConstructors() 方式可以获取到你所有的构造函数，是一个集合。
        Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();

        // 要循环比对出构造函数集合与入参信息 args 的匹配情况
        for (Constructor ctor : declaredConstructors) {
            if (args != null && ctor.getParameterTypes().length == args.length){
                constructorToUse = ctor;
                break;
            }
        }
        return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
    }

    protected InstantiationStrategy getInstantiationStrategy() {
        return instantiationStrategy;
    }
    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy){
        this.instantiationStrategy = instantiationStrategy;
    }
}
